package com.rpp.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author rpp
 * @Date 2020/8/17 9:25 下午
 */
@Activate(group = {CommonConstants.CONSUMER})
public class TPMonitorFilter implements Filter, Runnable {

    public TPMonitorFilter() {
        // 每隔5秒打印每个方法的tp90, tp99耗时
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this, 1, 5, TimeUnit.SECONDS);
    }

    /**
     * 记录请求响应时间，key为方法名称，value为响应时间数组
     */
    private static Map<String, List<Long>> responseTimes = new ConcurrentHashMap<>();

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        long start = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        long end = System.currentTimeMillis();

        long time = end - start;
        String methodName = invocation.getMethodName();

        //记录请求响应时间
        responseTimes.putIfAbsent(methodName, new ArrayList<>());
        responseTimes.get(methodName).add(time);

        return result;
    }

    /**
     * 间隔5秒统计一次,统计完成后清除之前记录的数据
     */
    @Override
    public void run() {
        aggregate();
    }

    /**
     * 统计每个方法的tp90, tp99耗时
     */
    private void aggregate() {
        Set<String> methods = responseTimes.keySet();
        Map<String, List<Long>> map = new ConcurrentHashMap<>();
        for (String method : methods) {
            List<Long> list = new ArrayList<>();
            list.addAll(responseTimes.get(method));
            map.put(method, list);
        }
        responseTimes = new ConcurrentHashMap<>();
        String timeString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        for (String method : methods) {

            List<Long> list = new ArrayList<>();
            list.addAll(map.get(method));
            Collections.sort(list);

            long tp90 = list.get((int) (list.size() * 0.90));
            long tp99 = list.get((int) (list.size() * 0.99));

            System.out.println(String.format("方法：%s 的tp90耗时：%s,tp99耗时：%s, 当前时间：%s",
                    method, tp90, tp99, timeString));
        }
        System.out.println("==================");
    }
}
